#include<iostream>
#include<string>
#include<vector>
#include<boost/filesystem.hpp>
#include"util.hpp"
//是一个目录，下面放的是所有html网页
const std::string src_path = "data/input";
const std::string output = "data/raw_html/raw.txt";

typedef struct DocInfo
{
	std::string title;//文档标题
	std::string content; //文档内容
	std::string url;//该文档在官网中url
}DocInfo_t;

//const &:输入
//*:输出
//&:输入输出
bool EnumFile(const std::string& src_path, std::vector<std::string>* files_list);
bool ParseHtml(const std::vector<std::string>& files_list, std::vector<DocInfo_t>* results);
bool SaveHtml(const std::vector<DocInfo_t>& results, const std::string &output);


int main()
{
	std::vector<std::string> files_list;
	//递归式把每个html文件名带路径保存到files_list中，方便后期进行一个一个文件读取

	if(!EnumFile(src_path, &files_list))
	{
		std::cerr << "enum file name error!" << std::endl;
		return 1;
	}
	//第二部：按照files_list中的文件名，逐个读取文件内容，进行解析
	std::vector<DocInfo_t> results;
	if(!ParseHtml(files_list,&results))
	{
		std::cerr << "parse html error!" << std::endl;
		return 2;
	}
	//第三步：把解析完的文件内容写入到output中，按照\3作为每个文档分隔符
	if(!SaveHtml(results,output))
	{
		std::cerr << "save html error!" << std::endl;
		return 3;
	}
	return 0;
}


bool EnumFile(const std::string& src_path, std::vector<std::string>* files_list)
{
	namespace fs = boost::filesystem;
	fs::path root_path(src_path);
	if(!fs::exists(root_path))
	{
		std::cerr << src_path << "not exist!" << std::endl;
		return false;
	}
	//定义一个给空的迭代器，用来进行判断递归结束
	fs::recursive_directory_iterator end;
	for(fs::recursive_directory_iterator iter(root_path);iter != end;++iter)
	{
		if(!fs::is_regular_file(*iter))
		{
			continue;
		}
		if(iter->path().extension() != ".html")
		{
			continue;
		}
		//std::cout << "debug:" << iter->path().string() << std::endl;
		//当前路径一定是一个合法的，以html结束的普通网页文件
		files_list->push_back(iter->path().string());
	}
	return true;
}

static bool ParseTitle(const std::string& file, std::string * title)
{
	std::size_t begin = file.find("<title>");
	if(begin == std::string::npos)
	{
		return false;
	}
	std::size_t end = file.find("</title>");
	if(end == std::string::npos)
	{
		return false;
	}
	begin += std::string("<title>").size();
	if(begin > end){return false;}
	*title = file.substr(begin,end-begin);
	return true;
}
		
static bool ParesContent(const std::string& file, std::string *content)
{

	//去标签,基于一个简易的状态机
	enum status{
		LABLE,
		CONTENT
	};
	
	enum status s = LABLE;
	for(char c : file)//只要碰到了>，就意味着当前标签处理完毕
	{
		switch(s)
		{
			case LABLE:
			if(c == '>') s = CONTENT;
			break;
			case CONTENT:
			if(c == '<') s = LABLE;
			else
			{
				//不保留原始文件中的\n
				if(c== '\n') c = ' ';
				content->push_back(c);
			}
			break;
			default:
			break;
		}
	}
	return true;
}
static bool ParseUrl(const std::string & file_path,std::string * url)
{
	std::string url_head = "https://www.boost.org/doc/libs/1_87_0/doc/html";
	std::string url_tail = file_path.substr(src_path.size());
	*url = url_head + url_tail;
	
	
	return true;

}

//for debug
 void showDoc(const DocInfo_t& doc)
{
	std::cout << "title:" << doc.title << std::endl;
	std::cout << "content:" << doc.content << std::endl;
	std::cout << "url:" << doc.url << std::endl;
}
bool ParseHtml(const std::vector<std::string>& files_list, std::vector<DocInfo_t>* results)
{
	for(const std::string &file :files_list)
	{
		//1,读取文件，Read()
		std::string result;
		if(!ns_util::FileUtil::ReadFile(file,&result))
		{
			continue;
		}
		DocInfo_t doc;
		//2,解析指定的文件，提取title
		if(!ParseTitle(result,&doc.title))
		{
			continue;
		}
		//3，解析指定的文件，提取content,就是去标签
		if(!ParesContent(result,&doc.content))
		{
			continue;
		}
		//4，解析指定的文件，提取url
		if(!ParseUrl(file,&doc.url))
		{
			continue;
		}
		//done,一定是完成了解析任务，当前文档相关结果都在doc里面
		
		results->push_back(std::move(doc));//细节，本质会发生拷贝，效率会比较低
		
		//for debug
		//showDoc(doc);
	
	}
	return true;
}
bool SaveHtml(const std::vector<DocInfo_t>& results, const std::string &output)
{
	#define SEP '\3'
	//按照二进制方式写入
	std::ofstream out(output,std::ios::out | std::ios::binary);
	if(!out.is_open())
{
	std::cerr << "open file error!" << std::endl;
	return false;
}

//就可进行文件内容写入

for(auto & item : results)
{
	std::string out_string;
	out_string = item.title;
	out_string += SEP;
	out_string += item.content;
	out_string += SEP;
	out_string += item.url;
	out_string += '\n';
	out.write(out_string.c_str(),out_string.size());
}
out.close();
	return true;
}
